import casbin
import casbin_async_sqlalchemy_adapter
from fastapi import Depends, Request
from app.common.jwt import DependsJwtAuth
from app.database.db import async_engine
from app.common.exception.errors import AuthorizationError
from app.models.casbin_rule import CasbinRule


class RBAC:
    @staticmethod
    async def enforcer() -> casbin.AsyncEnforcer:
        _CASBIN_RBAC_MODEL_CONF_ = """
        [request_definition]
        r = sub, obj, act

        [policy_definition]
        p = sub, obj, act

        [role_definition]
        g = _, _

        [policy_effect]
        e = some(where (p.eft == allow))

        [matchers]
        m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
        """
        adapter = casbin_async_sqlalchemy_adapter.Adapter(
            async_engine,
            db_class=CasbinRule,
        )
        model = casbin.AsyncEnforcer.new_model(_CASBIN_RBAC_MODEL_CONF_)
        enforcer = casbin.AsyncEnforcer(model, adapter=adapter)
        await enforcer.load_policy()
        return enforcer

    async def rbac_verify(self, request: Request, _token: str = DependsJwtAuth) -> None:
        path = request.url.path
        user_uuid = request.user.uuid
        method = request.method
        enforcer = await self.enforcer()
        if not enforcer.enforce(user_uuid, path, method):
            raise AuthorizationError


rbac: RBAC = RBAC()
DependsRBAC = Depends(rbac.rbac_verify)
